import SCAFlexible as scf;
import SCArchive as sca;

const CommandLength = 12;




const ackMax = 0x20;
const MapDim = 0x600;
var DisConnectCode = 0xFFFF;


var MSQCSpecial = 0;
var MSQCCondiction = 0;
var MSQCValue = 0;

const MSQCSpecialBuffer = PVariable();
const MSQCBuffer = PVariable();

function Init(){
	EUDRegisterObjectToNamespace("MSQCSpecial", MSQCSpecial);
	EUDRegisterObjectToNamespace("MSQCSpecialBuffer", MSQCSpecialBuffer);
	EUDRegisterObjectToNamespace("MSQCCondiction", MSQCCondiction);
	EUDRegisterObjectToNamespace("MSQCValue", MSQCValue);
	EUDRegisterObjectToNamespace("MSQCBuffer", MSQCBuffer);
}


var SCAUseUserMessage = 1;
const SCALastMessage = PVariable();
/*
1 = 연결됨
2 = 연결 끊킴
3 = 로드중
4 = 로드 완료
5 = 세이브중
6 = 세이브 완료
7 = 런처와 먼저 연결하세요
8 = 다른 작업 중입니다.
9 = 작업 실패
*/





var LastTick;


const ConnectStatus = PVariable();
const MaxBuffer = PVariable();
const BaseAddrEPD = PVariable();
const LoadAddrEPD = PVariable();
var index;
const rn = PVariable();
const ack = PVariable();
const SCACommand = PVariable();
const DataSlot = PVariable();
function ReceiveValue(value){
	const CP = getcurpl();
	value = value % 0x10000 + (value / 0x10000) * MapDim;
	ack[CP] = value / 0x10000;
	value = value % 0x10000;
	return value;
}

function SendValue(seq){
	const CP = getcurpl();
	const rseq = seq - 1;
	var value = wread_epd(BaseAddrEPD[CP] + rseq / 2, (rseq % 2) * 2);

	seq = seq % ackMax + 1;
	value += seq * 0x10000;
	
	if (Memory(0x57F1B0,Exactly,CP)){
		MSQCValue = value % MapDim + (value / MapDim) * 0x10000;
	}
}





const DateLoadStatus = PVariable();
const GlobalDataLoadStatus = PVariable();


//const st = StringBuffer(100);

function LoadDataRead(dataLen){
	const CP = getcurpl();
	
	switch(SCACommand[CP]){
		case 1:
			for(var i = 0 ; i < scf.ObjectCount; i++){
				scf.ResetValue(i, 0);
			}
			
			for(var i = 0 ; i < dataLen; i++){
				i = scf.LoadDataReadValue(LoadAddrEPD[CP], i);

				/*
				const indicator = wread_epd(LoadAddrEPD[CP] + i / 2, (i % 2) * 2);
				
				if (indicator != 0){
					const spec = indicator / 0x1000;
					const ObjNum = indicator % 0x1000;
				
					var value = 0;
					if (spec == 1){
						//4바이트 지정
						i++;
						const value1 = wread_epd(LoadAddrEPD[CP] + i / 2, (i % 2) * 2);
						i++;
						const value2 = wread_epd(LoadAddrEPD[CP] + i / 2, (i % 2) * 2);
					
						value = value1 * 0x10000 + value2;
					}else if (spec == 2){
						//2바이트 지정
						i++;
						value = wread_epd(LoadAddrEPD[CP] + i / 2, (i % 2) * 2);
					
					}
					
					//st.print("값 받음 : ", value);
					scf.SaveValue(ObjNum, value, 0);
				}*/
			}
			break;
		case 2:
			//날짜  YYYM D H M W
			const BaseAddres = LoadAddrEPD[CP];
			
			const aYM = dwread_epd(BaseAddres);
			sca.Year = aYM / 0x10;
			sca.Month = aYM % 0x10;
			
			sca.Day = bread_epd(BaseAddres + 1, 3);
			sca.Hour = bread_epd(BaseAddres +1, 2);
			sca.Min = bread_epd(BaseAddres + 1, 1);
			sca.Week = bread_epd(BaseAddres + 1 , 0);
			
			DateLoadStatus[CP] = 1;
			break;
		case 3:
			//맵 변수
			var value = 0;
			
			for(var i = 0 ; i < 20; i++){
				sca.GlobalData[i] = 0;
			}

			for(var i = 0 ; i < dataLen; i++){
				const insepector = wread_epd(LoadAddrEPD[CP] + i / 2, (i % 2) * 2);
				if (insepector != 0){
					const vsize = insepector / 0x100;
					const index = insepector % 0x100;


					if (vsize == 1){
						i++;
						const value1 = wread_epd(LoadAddrEPD[CP] + i / 2, (i % 2) * 2);
						i++;
						const value2 = wread_epd(LoadAddrEPD[CP] + i / 2, (i % 2) * 2);
						value = value1 * 0x10000 + value2;
					}else if(vsize == 2){
						i++;
						value = wread_epd(LoadAddrEPD[CP] + i / 2, (i % 2) * 2);
					}

					sca.GlobalData[index] = value;
				}
				

			}
			GlobalDataLoadStatus[CP] = 1;
			break;
	}
}


function SaveDataWrite(){
	const CP = getcurpl();
	var index = 0;
	
	for(var i = 0 ; i < scf.ObjectCount; i++){
		index = scf.SaveDataWriteValue(i,BaseAddrEPD[CP],index);

		/*
		const objValue = scf.LoadValue(i, 0);
		if(objValue != 0){
			if (objValue > 0xFFFF){
				wwrite_epd(BaseAddrEPD[CP] + index / 2, (index % 2) * 2, 0x1000 + i);
				index++;
				wwrite_epd(BaseAddrEPD[CP] + index / 2, (index % 2) * 2, objValue / 0x10000);
				index++;
				wwrite_epd(BaseAddrEPD[CP] + index / 2, (index % 2) * 2, objValue % 0x10000);
				index++;
			}else{
				wwrite_epd(BaseAddrEPD[CP] + index / 2, (index % 2) * 2, 0x2000 + i);
				index++;
				wwrite_epd(BaseAddrEPD[CP] + index / 2, (index % 2) * 2, objValue);
				index++;
			}
		}
		*/
		//st.print("값 저장 : ", objValue);
		
	}
	wwrite_epd(BaseAddrEPD[CP] + index / 2, (index % 2) * 2, 0);
	index++;
	wwrite_epd(BaseAddrEPD[CP] + index / 2, (index % 2) * 2, 0);
	index++;
	wwrite_epd(BaseAddrEPD[CP] + index / 2, (index % 2) * 2, 0);
	index++;
}

const CheckIntegrityFlag = PVariable();
function CheckIntegrity(){
	const CP = getcurpl();

	if (Memory(0x57F1B0,Exactly,CP)){
		const BaseEPD = BaseAddrEPD[CP];
		const LoadEPD = LoadAddrEPD[CP];
	
		for(var i = 0 ; i < scf.SpaceLength / 4; i++){
			const value1 = dwread_epd(BaseEPD + i);
			const value2 = dwread_epd(LoadEPD + i);
		

			//둘다 0일경우 루프 탈출
			if(MSQCSpecial == 0 && (value1 == 0 && value2 == 0)){
				MSQCSpecial = 3;
			}
		
			if(MSQCSpecial == 0 && value1 != value2){
				MSQCSpecial = 4;
			}
		}
	}
}


function DataLoad();
var TimeOut;

var LastPing;
var DisConnectTimer;
var ConnectingTimer;
var ConnectingPoint;
function PlayerExec(){
	const CP = getcurpl();
	const CurrentTime = dwread_epd(EPD(0x51CE8C));
	const FrameTick = (LastTick - CurrentTime);
	
	
	
	
	
	//커넥트 상태를 판단.
	const Ping = wread_epd(EPD(scf.ws) + scf.EntryPointLength, 0);
	if (Memory(0x57F1B0,Exactly,CP)){
		if (LastPing != Ping){
			if (ConnectStatus[CP] == 0){
				const CurrentConnectingTimer = (ConnectingTimer - CurrentTime);
				if (CurrentConnectingTimer > 500){
					if (ConnectingPoint == 0){
						ConnectingTimer = CurrentTime;
						ConnectingPoint++;
					}else{
						ConnectingTimer = 0;
							MSQCSpecial = 1;
					}
				}
			}

			LastPing = Ping;
			DisConnectTimer = CurrentTime;
		}else{
			if (ConnectStatus[CP] == 0){
				const CurrentConnectingTimer = (ConnectingTimer - CurrentTime);
				if (CurrentConnectingTimer > 1000){
					ConnectingTimer = CurrentTime;
					ConnectingPoint = 0;
				}
			}
		}
	}



	
	if (ConnectStatus[CP] == 1){
		if (Memory(0x57F1B0,Exactly,CP)){
			const CurrentDisConnectTimer = (DisConnectTimer - CurrentTime);
			if (CurrentDisConnectTimer > 500){
				wwrite_epd(EPD(scf.ws) + scf.EntryPointLength, 0, 0);
				LastPing = 0;
				MSQCSpecial = 2;
			}
		}



		if(MSQCSpecialBuffer[CP] == 200){
		    const orderAddrEPD = EPD(scf.ws) + scf.EntryPointLength;
			ConnectStatus[CP] = 0;
			MSQCSpecialBuffer[CP] = 0;
			SCACommand[CP] = 0;
			SCALastMessage[CP] = 2;
			if (SCAUseUserMessage == 1){
				PlayWAV("sound\\Bullet\\tscFir00.wav");
	            f_eprintln("\x03SCArchive\x04와 \x07연결\x04이 \x08끊어졌습니다.");
	        }

			if (Memory(0x57F1B0,Exactly,CP)){
				MSQCSpecial = 0;
				wwrite_epd(EPD(scf.ws) + scf.EntryPointLength, 0, 0);
				LastPing = 0;
				bwrite_epd(orderAddrEPD, 2, 0);
    			bwrite_epd(orderAddrEPD, 3, 0);
				MSQCCondiction = 0;
			}
		}

	
	
	
	    switch(SCACommand[CP]) {
		    case 1:
		    case 2:
		    case 3:
		    	const orderAddrEPD = EPD(scf.ws) + scf.EntryPointLength;
				if (Memory(0x57F1B0,Exactly,CP)){
		    		//데이터 슬롯 번호를 기록한다.
		    		bwrite_epd(orderAddrEPD + 1, 0, DataSlot[CP]);
		    		//런처에게 요청한다.
		    		bwrite_epd(orderAddrEPD, 2, SCACommand[CP]);
				}


		    	
		    	//런처가 데이터를 올렸는지 판단한다.
		    	const LauncherStatus = bread_epd(orderAddrEPD, 3);
				if (SCAUseUserMessage == 1){
					if(rn[CP] == 1){
						f_eprintln("\x07불러오기 : \x03SCArchive\x04의 \x1F응답\x04을 \x07기다리는 중...");
					}else if(CheckIntegrityFlag[CP] == 0){
						f_eprintln("\x07불러오기 : \x03데이터 불러오는 중 ... \x1FPage : ", rn[CP]);
					}else if(CheckIntegrityFlag[CP] == 1){
						f_eprintln("\x07불러오기 : \x03전달 오류를 판단하는 중 ... ");
					}
				}
		    	

				if(CheckIntegrityFlag[CP] == 0){
					if (Memory(0x57F1B0,Exactly,CP)){
						MSQCCondiction = 1;
					}
				
					//Receiver
					{const RecevieValue = ReceiveValue(MSQCBuffer[CP]);
			
					if(ack[CP] == (rn[CP] % ackMax + 1)){
						//st.print("값 전달 받음      rn : ",rn[CP] , " ack : " , ack[CP] , " Value : " ,RecevieValue);
						const rseq = rn[CP] - 1;
						wwrite_epd(LoadAddrEPD[CP] + rseq / 2, (rseq % 2) * 2, RecevieValue);
						rn[CP] += 1;
					}else if(ack[CP] == 0 && RecevieValue == 0xFFFF){
						MaxBuffer[CP] = rn[CP] - 1;
					}else{
						const CurrentTimeer = (TimeOut - CurrentTime);
						if (CurrentTimeer > 500){
							TimeOut = CurrentTime;
							index = rn[CP];
						}
					}}
					
					
					//Sender
					if(LauncherStatus == 1){
						const rseq = index - 1;
						const CheckZero = dwread_epd(BaseAddrEPD[CP] + rseq / 2);
						//커낵션을 끊을때는 특수한 값을 넘겨준다
						if (CheckZero == 0){
							//커낵션 끊는 값을 넘겨준다
							if (Memory(0x57F1B0,Exactly,CP)){
								MSQCValue = DisConnectCode % MapDim + (DisConnectCode / MapDim) * 0x10000;
							}
						}else{
							SendValue(index);
							if (FrameTick > 70){
								LastTick = CurrentTime;
								index += 1;
							}
						}
					}
				}

		
			
				//End
				{if (rn[CP] > MaxBuffer[CP]){
					const rseq = MaxBuffer[CP];
					dwwrite_epd(LoadAddrEPD[CP] + rseq / 2, 0);
					
					
					switch(CheckIntegrityFlag[CP]){
						case 0:
							if (Memory(0x57F1B0,Exactly,CP)){
								MSQCCondiction = 0;
							}
							CheckIntegrity();
							CheckIntegrityFlag[CP] = 1;
							break;
						case 1:
							CheckIntegrity();
	
							if(MSQCSpecialBuffer[CP] == 300){
								//통과
								CheckIntegrityFlag[CP] = 2;
								MSQCSpecialBuffer[CP] = 0;
								if (Memory(0x57F1B0,Exactly,CP)){
									MSQCSpecial = 0;
								}
							}
							if(MSQCSpecialBuffer[CP] == 400){
								CheckIntegrityFlag[CP] = 0;
								MaxBuffer[CP] = scf.SpaceLength / 2;
								rn[CP] = 1;
								ack[CP] = 0;
								if (Memory(0x57F1B0,Exactly,CP)){
									MSQCSpecial = 0;
									index = 1;
								}
							}
							break;
						case 2:
							if (Memory(0x57F1B0,Exactly,CP)){
				    			bwrite_epd(orderAddrEPD, 2, 0);
				    			bwrite_epd(orderAddrEPD, 3, 0);
								MSQCValue = 0;
								MSQCCondiction = 0;
							}
							LoadDataRead(rn[CP] - 1);
							SCACommand[CP] = 0;
							
							SCALastMessage[CP] = 4;
							if (SCAUseUserMessage == 1){
								PlayWAV("sound\\Misc\\TDrTra01.wav");
								f_eprintln("\x07성공적으로 \x03데이터\x04를 불러왔습니다.");
							}
							break;
					}
				}}
		        break;
			case 4:
				if (Memory(0x57F1B0,Exactly,CP)){
					//데이터 슬롯 번호를 기록한다.
					bwrite_epd(orderAddrEPD + 1, 0, DataSlot[CP]);

					//런처에게 알려준다.
					bwrite_epd(orderAddrEPD, 2, SCACommand[CP]);
				
				}


		    	
		    	//런처가 데이터를 받았는지 판단한다.
		    	const LauncherStatus2 = bread_epd(orderAddrEPD, 3);
		    	if(LauncherStatus2 == 1){
		    		//데이터 받은거임
    				if (Memory(0x57F1B0,Exactly,CP)){
						MSQCValue = 100;
						MSQCCondiction = 1;
					}
		    	}
		    	if(MSQCBuffer[CP] == 100){
	    				if (Memory(0x57F1B0,Exactly,CP)){
			    			bwrite_epd(orderAddrEPD, 2, 0);
			    			bwrite_epd(orderAddrEPD, 3, 0);
							MSQCValue = 0;
							MSQCCondiction = 0;
						}
						SCACommand[CP] = 0;
						
						SCALastMessage[CP] = 6;
						if (SCAUseUserMessage == 1){
							PlayWAV("sound\\Misc\\TDrTra01.wav");
							f_eprintln("\x07성공적으로 \x03데이터\x04를 저장했습니다.");
						}
		    	}
		        break;
	    }
	}else{
		if(MSQCSpecialBuffer[CP] == 100){
			ConnectStatus[CP] = 1;
			MSQCSpecialBuffer[CP] = 0;
			SCALastMessage[CP] = 1;
			if (SCAUseUserMessage == 1){
				PlayWAV("sound\\Misc\\ZRescue.wav");
	            f_eprintln("\x03SCArchive\x04와 \x07연결\x04되었습니다.");
			}
			if (Memory(0x57F1B0,Exactly,CP)){
				MSQCSpecial = 0;
			}
		}
	}


	

}

function Exec(){
	EUDPlayerLoop()();
	PlayerExec();
	EUDEndPlayerLoop();
}


function DataLoad(Slot){
	const CP = getcurpl();
	
	if (ConnectStatus[CP] == 1){
		if (SCACommand[CP] == 0){
			DataSlot[CP] = Slot;
			BaseAddrEPD[CP] = EPD(scf.ws) + scf.EntryPointLength + CommandLength / 4;
			LoadAddrEPD[CP] = EPD(scf.ws) + scf.EntryPointLength + CommandLength / 4 + ((scf.SpaceLength + CommandLength) * (CP + 1)) / 4;
			
					
			LastTick = dwread_epd(EPD(0x51CE8C));
			
			SCALastMessage[CP] = 3;
			if (SCAUseUserMessage == 1){
				PlayWAV("sound\\glue\\swishin.wav");
			}
			CheckIntegrityFlag[CP] = 0;
			MaxBuffer[CP] = scf.SpaceLength / 2;
			rn[CP] = 1;
			ack[CP] = 0;
			if (Memory(0x57F1B0,Exactly,CP)){
				MSQCValue = 0;
				index = 1;
			}
			SCACommand[CP] = 1;
			MSQCBuffer[CP] = 0;
		}else{
			SCALastMessage[CP] = 8;
			if (SCAUseUserMessage == 1){
				PlayWAV("sound\\Misc\\PError.WAV");
	            f_eprintln("\x08현재 다른 작업중입니다.");
	        }
	    }
	}else{
		SCALastMessage[CP] = 7;
		if (SCAUseUserMessage == 1){
			PlayWAV("sound\\Misc\\PError.WAV");
            f_eprintln("\x08데이터를 불러오기 위해선 SCArchive와 연결되어야 합니다.");
        }
    }
}


function DataSave(Slot){
	const CP = getcurpl();
	
	if (ConnectStatus[CP] == 1){
		if (SCACommand[CP] == 0){
			DataSlot[CP] = Slot;
			BaseAddrEPD[CP] = EPD(scf.ws) + scf.EntryPointLength + CommandLength / 4;

			if (Memory(0x57F1B0,Exactly,CP)){
				SaveDataWrite();
			}

			MSQCBuffer[CP] = 0;
			SCALastMessage[CP] = 5;
			if (SCAUseUserMessage == 1){
				PlayWAV("sound\\glue\\swishin.wav");
			}
			
			SCACommand[CP] = 4;
		}else{
			SCALastMessage[CP] = 8;
			if (SCAUseUserMessage == 1){
				PlayWAV("sound\\Misc\\PError.WAV");
	            f_eprintln("\x08현재 다른 작업중입니다.");
	        }
	    }
	}else{
		SCALastMessage[CP] = 7;
		if (SCAUseUserMessage == 1){
			PlayWAV("sound\\Misc\\PError.WAV");
            f_eprintln("\x08데이터를 저장하기 위해선 SCArchive와 연결되어야 합니다.");
        }
    }	
}



function GetDate(){
	const CP = getcurpl();
	if (ConnectStatus[CP] == 1){
		if (SCACommand[CP] == 0){
			BaseAddrEPD[CP] = EPD(scf.ws) + scf.EntryPointLength + CommandLength / 4;
			LoadAddrEPD[CP] = EPD(scf.ws) + scf.EntryPointLength + CommandLength / 4 + ((scf.SpaceLength + CommandLength) * (CP + 1)) / 4;
			
					
			LastTick = dwread_epd(EPD(0x51CE8C));
			
			SCALastMessage[CP] = 3;
			if (SCAUseUserMessage == 1){
				PlayWAV("sound\\glue\\swishin.wav");
			}
			CheckIntegrityFlag[CP] = 0;
			MaxBuffer[CP] = scf.SpaceLength / 2;
			rn[CP] = 1;
			ack[CP] = 0;
			if (Memory(0x57F1B0,Exactly,CP)){
				MSQCValue = 0;
				index = 1;
			}
			SCACommand[CP] = 2;
			MSQCBuffer[CP] = 0;
		}else{
			SCALastMessage[CP] = 8;
			if (SCAUseUserMessage == 1){
				PlayWAV("sound\\Misc\\PError.WAV");
	            f_eprintln("\x08현재 다른 작업중입니다.");
	        }
	    }
	}else{
		SCALastMessage[CP] = 7;
		if (SCAUseUserMessage == 1){
			PlayWAV("sound\\Misc\\PError.WAV");
            f_eprintln("\x08데이터를 불러오기 위해선 SCArchive와 연결되어야 합니다.");
        }
    }
}


function LoadGlobalData(){
	const CP = getcurpl();
	if (ConnectStatus[CP] == 1){
		if (SCACommand[CP] == 0){
			BaseAddrEPD[CP] = EPD(scf.ws) + scf.EntryPointLength + CommandLength / 4;
			LoadAddrEPD[CP] = EPD(scf.ws) + scf.EntryPointLength + CommandLength / 4 + ((scf.SpaceLength + CommandLength) * (CP + 1)) / 4;
			
					
			LastTick = dwread_epd(EPD(0x51CE8C));
			
			SCALastMessage[CP] = 3;
			if (SCAUseUserMessage == 1){
				PlayWAV("sound\\glue\\swishin.wav");
			}
			CheckIntegrityFlag[CP] = 0;
			MaxBuffer[CP] = scf.SpaceLength / 2;
			rn[CP] = 1;
			ack[CP] = 0;
			if (Memory(0x57F1B0,Exactly,CP)){
				MSQCValue = 0;
				index = 1;
			}
			SCACommand[CP] = 3;
			MSQCBuffer[CP] = 0;
		}else{
			SCALastMessage[CP] = 8;
			if (SCAUseUserMessage == 1){
				PlayWAV("sound\\Misc\\PError.WAV");
	            f_eprintln("\x08현재 다른 작업중입니다.");
	        }
	    }
	}else{
		SCALastMessage[CP] = 7;
		if (SCAUseUserMessage == 1){
			PlayWAV("sound\\Misc\\PError.WAV");
            f_eprintln("\x08데이터를 불러오기 위해선 SCArchive와 연결되어야 합니다.");
        }
    }
}

